﻿using System;

namespace SimpleServiceBus.Bus.Pipeline.PipelineComponents.Routing
{
    public enum RoutingStyle
    {
        Forward = 0,
        Redirect
    }

    public enum RouteNotFoundBehavior
    {
        Automatic = 0,
        DiscardMessage,
        DiscardMessageAndReplyWithError,
        PassMessageToNextPipelineComponent
    }

    public abstract class MessageRouterComponentBase : PipelineComponentBase
    {
        public RoutingStyle RoutingStyle { get; set; }
        public RouteNotFoundBehavior RouteNotFoundBehavior { get; set; }

        public event EventHandler<RouteNotFoundEventArgs> RouteNotFound;

        protected override void ProcessMessage(MessageEnvelope messageEnvelope, IMessageContext context)
        {
            string[] destinations = GetDestinationsForMessage(messageEnvelope, context);
            if (destinations != null && destinations.Length > 0)
            {
                context.Endpoint.MessageBus.Forward(messageEnvelope, destinations);

                if (RoutingStyle == RoutingStyle.Redirect)
                    context.AbortMessageProcessing = true;
            }
            else
            {
                OnRouteNotFound(context);
            }
        }

        protected abstract string[] GetDestinationsForMessage(MessageEnvelope messageEnvelope, IMessageContext context);

        protected virtual void OnRouteNotFound(IMessageContext messageContext)
        {
            var args = new RouteNotFoundEventArgs
                           {
                               RouteNotFoundBehavior = RouteNotFoundBehavior,
                               MessageContext = messageContext
                           };

            EventHandler<RouteNotFoundEventArgs> evt = RouteNotFound;
            if (evt != null)
                evt(this, args);

            ApplyRouteNotFoundBehavior(args.RouteNotFoundBehavior, messageContext);
        }

        protected virtual void ApplyRouteNotFoundBehavior(RouteNotFoundBehavior behavior, IMessageContext messageContext)
        {
            if (behavior == RouteNotFoundBehavior.Automatic)
            {
                if (RoutingStyle == RoutingStyle.Forward)
                    ApplyRouteNotFoundBehavior(RouteNotFoundBehavior.PassMessageToNextPipelineComponent, messageContext);
                else
                    ApplyRouteNotFoundBehavior(RouteNotFoundBehavior.DiscardMessageAndReplyWithError, messageContext);
                return;
            }

            if (behavior == RouteNotFoundBehavior.PassMessageToNextPipelineComponent)
                return;

            messageContext.AbortMessageProcessing = true;

            if (behavior == RouteNotFoundBehavior.DiscardMessageAndReplyWithError)
            {
                //TODO:Send Error
                //Bus.Send(new Error)
            }
        }
    }

    public class RouteNotFoundEventArgs : EventArgs
    {
        public RouteNotFoundBehavior RouteNotFoundBehavior { get; set; }
        public IMessageContext MessageContext { get; set; }
    }
}